/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Model;

import GUI.EnigmaGUIMainWindow;
import Actors.Actor;
import Actors.HumanControlledBall;
import Controller.EnigmaController;
import Controller.NormalGameController;
import Controller.ReplayGameController;
import java.util.Vector;
import EnigmaUtils.LevelGenerator;
import java.io.*;

/**
 *
 * @author Snowangelic
 */
public class EnigmaModel implements PlayerBallListener{
    public static final int GAME_NOT_STARTED=0;
    public static final int GAME_PLAYING=1;
    public static final int GAME_PAUSED=2;
    public static final int PLAYER_WON=3;
    public static final int PLAYER_LOST=4;
    public static final int GAME_READY=5;
    
    Vector<GameStateListener> gameStateListeners;

    ActorManager actorManager;
    OxydeManager oxydeManager;
    Plateau plate;
    Inventory inventory;
    Clock clock;

    //GamePanel gp;
    EnigmaGUIMainWindow gui;
    EnigmaController controller;
    int gameState;

    public EnigmaModel(EnigmaGUIMainWindow win,PlateauListener plateauListener,ActorManagerListener actorManagerListener,InventoryListener inventoryListener,ClockListener clockListener,GameStateListener gameStateListener,PlayerBallListener playerBallListener ){
        System.out.println("Building Model");

        gameStateListeners=new Vector<GameStateListener>();
        gameStateListeners.add(gameStateListener);

        actorManager=new ActorManager(this);
        actorManager.addListener(actorManagerListener);
        actorManager.addPlayerBallListener(playerBallListener);

        oxydeManager=new OxydeManager();
        oxydeManager.setModel(this);

        plate=new Plateau(this);
        plate.addListener(plateauListener);
        plate.addListener(oxydeManager);

        inventory=new Inventory();
        inventory.addListener(inventoryListener);
        inventory.addListener(plate);
        inventory.addListener(actorManager);

        clock=new Clock();
        clock.addListener(clockListener);

        actorManager.addListener(plate);
        actorManager.addPlayerBallListener(inventory);
        actorManager.addPlayerBallListener(this);

        plate.addCollisionListener(inventory);

        /*
        plate.generateLevel();
        HumanControlledBall ball=new HumanControlledBall();
        ball.setModel(this);
        actorManager.addActor(ball);
        */

        setGameState(0);
        gui=win;

    }

    public void addGameStateListener(GameStateListener listener){
        if(!gameStateListeners.contains(listener))
            gameStateListeners.add(listener);
    }

    public double[] getUserImpulse() {
        return controller.getImpulse();
    }

    public void loadLevel(File file) throws FileNotFoundException, IOException {
        File level=null;
        String filename = file.toString();
        String ext = filename.substring(filename.lastIndexOf('.')+1, filename.length());

        if(ext.equals("exl")){
            controller = new NormalGameController(this, gui, file);
            level=file;
        }
        else{
            FileInputStream fis = new FileInputStream(file);

            // Here BufferedInputStream is added for fast reading.
            BufferedInputStream bis = new BufferedInputStream(fis);
            DataInputStream dis = new DataInputStream(bis);
            String levelFileStr=dis.readLine();
            level = new File(levelFileStr);
            controller = new ReplayGameController(this, gui, file);
        }
        LevelGenerator parser=new LevelGenerator(level);
        parser.generateLevel(inventory,actorManager,plate);
        setGameState(GAME_PLAYING);
    }

    public void pauseGame() {
        if(gameState==GAME_READY) setGameState(GAME_PLAYING);
        else if(gameState==GAME_PLAYING) setGameState(GAME_PAUSED);
        else if(gameState==GAME_PAUSED) setGameState(GAME_PLAYING);
    }

    public void update(long dtime){
        //System.out.println("Updating model with : dtime="+dtime+" and mouseX= "+mouseX+" and mouseY= "+mouseY);

        //if(dtime>0)System.out.println("Updating model with : dtime="+dtime+" and mouseX= "+mouseX+" and mouseY= "+mouseY);

        if(gameState==GAME_PLAYING){
            actorManager.update(dtime);
            inventory.update(dtime);
            clock.update(dtime);
            plate.updateItems(dtime);
            plate.updateFloors(dtime);
            plate.updateStones(dtime);
        }
        gui.repaint();
    }

    public void gameFinished(){
        setGameState(PLAYER_WON);
    }

    /*
    public void actorEntersCase(Actor actor, int xIndex, int yIndex) {
        plate.actorEntersCase(actor,xIndex,yIndex);
    }

    public void actorLeavesCase(Actor actor, int xIndex, int yIndex) {
        plate.actorLeavesCase(actor,xIndex,yIndex);
    }

    public void actorCollidesWith(Actor actor, int xIndex, int yIndex, CollisionType type) {
        plate.actorCollidesWith(actor,xIndex,yIndex,type);
    }
     * */

    public double getFriction(int xIndex, int yIndex) {
        return plate.getFriction(xIndex, yIndex);
    }

    public double[] getPlateImpulse(Actor actor) {
        return plate.getImpulse(actor);
    }

    public Case getCase(int xIndex, int yIndex){
        return plate.getCase(xIndex, yIndex);
    }

    public void addToInventory(Items.Item item){
        inventory.addItem(item);
    }

    public void scrollInventory(){
        if(gameState==GAME_PLAYING)
            inventory.scroll();
    }

    public void useActiveItem(){
        if(gameState==GAME_PLAYING)
            inventory.useItem();

    }

    public void setGameState(int gameState){
        this.gameState=gameState;
        
        // fix immondissime pour le début du jeu
        if(gameState==GAME_PLAYING)getUserImpulse();
        
        for(GameStateListener listener : gameStateListeners)
            listener.gameStateChanged(gameState);

    }


    public void ballMoved(ActorEvent e) {
    }

    public void playerKilled(ActorEvent e) {
        if(inventory.removeExtraLife()){
            HumanControlledBall ball=new HumanControlledBall();
            actorManager.addActor(ball);
        }

        else setGameState(PLAYER_LOST);
    }

}
